package cz.cuni.amis.episodic.bayes.memories;

import cz.cuni.amis.episodic.bayes.utils.MemChart;
import cz.cuni.amis.episodic.bayes.utils.NodeSnapshot;
import cz.cuni.amis.episodic.bayes.utils.Utils;
import cz.cuni.amis.episodic.bayes.utils.chart.GraphPaintingDevice;
import cz.cuni.amis.episodic.dybanem.DBN;
import cz.cuni.amis.episodic.dybanem.Evidence;

import java.awt.Point;
import java.io.IOException;
import java.util.Collection;

/**
 *
 * @author ik
 */
public class IntervalSurpriseMemoryCreator extends PointSurpriseMemoryCreator {

    public IntervalSurpriseMemoryCreator(GraphPaintingDevice graphPaintingDevice) {
        super(graphPaintingDevice);
        strategyName = "retro_interval";
    }

    @Override
    public MemoryElement createMemoryInternal(String[] targets, NodeSnapshot[] trueSnapshots, DBN dbn, Collection<? extends Evidence> evidences, int iteration) {
     
        // compute KL from current knowledge to the real state
        //double[][] kl = Utils.computeKL(currentSnapshots, trueSnapshots);
    	double[][] kl = Utils.computeKL(trueSnapshots, currentSnapshots);

        // find max index
        Object[] maxRes = Utils.maxIndex(kl);
        Point idx = (Point) maxRes[0];
        double[] distr = trueSnapshots[idx.x].getProbability()[idx.y];
        int maxIx = Utils.maxIndex(distr);
        String node = targets[idx.x];
        // remember it
        int start = findMaxEqualsBack(trueSnapshots[idx.x].getProbability(), idx.y, maxIx);
        int end = findMaxEqualsFront(trueSnapshots[idx.x].getProbability(), idx.y, maxIx);
        MemoryElement mem = new MemoryElement(node, start, end, (double) maxRes[1], dbn.getNet().getOutcomeIds(node)[Utils.maxIndex(distr)]);

        // draw graph 
        if (graphPaintingDevice != null) {
            mem.markInKLGraph(kl[idx.x]); // we set this only because of drawing, NaN has specal color and here it indicates the max value        
            drawKLGraph(kl, targets, iteration);
        }

        return mem;
    }

    /**
     *
     * @param probability
     * @param time
     * @param maxIx
     * @return beginning of the interval where the max outcome was the same as
     * given maxIx
     */
    int findMaxEqualsBack(double[][] probability, int time, int maxIx) {
        //for(int i = time - 1; i >= 0; i--) {        }
        if (time < 0) {
            return 0;
        }
        if (Utils.maxIndex(probability[time]) == maxIx) {
            return findMaxEqualsBack(probability, time - 1, maxIx);
        } else {
            return time + 1;
        }
    }

    int findMaxEqualsFront(double[][] probability, int time, int maxIx) {
        //for(int i = time - 1; i >= 0; i--) {        }
        if (time >= probability.length) {
            return probability.length - 1;
        }
        if (Utils.maxIndex(probability[time]) == maxIx) {
            return findMaxEqualsFront(probability, time + 1, maxIx);
        } else {
            return time - 1;
        }
    }
}
